<?php

/**
* alltosun.com 支付宝M控制器 index.php
* ============================================================================
* 版权所有 (C) 2009-2014 北京互动阳光科技有限公司，并保留所有权利。
* 网站地址: http://www.alltosun.com
* ----------------------------------------------------------------------------
* 许可声明: 这是一个开源程序，未经许可不得将本软件的整体或任何部分用于商业用途及再发布。
* ============================================================================
* $Author: 吴松键 (wusj@alltosun.com) $
* $Date: 2014-9-25 下午2:09:54 $
* $Id$
*/

class Action
{
    private $alipay_config;
    private $user_id;

    public function __construct()
    {
        require_once MODULE_PATH.'/openapi/config/alipay_config.php';
        header("Content-type:text/html;charset=utf-8");

        $this->alipay_config = array(
            // 此三参数放到了根据订单获取
            //'partner'            => Config::get('partner'),
            //'key'                => Config::get('alipay_key'),
            //'seller_email'       => Config::get('seller_email'),
            'input_charset'      => Config::get('input_charset'),
            'transport'          => Config::get('transport'),
            'sign_type'          => Config::get('sign_type'),
            'cacert'             => Config::get('cacert'),
            'alipay_gateway_new' => Config::get('alipay_m_geteway'),
        );
        $this->user_id = user_helper::get_user_id();
    }

    /*
     * 支付
     */
    public function pay()
    {
        $order_id = Request::getParam('order_id', 0);
        if (!$this->user_id) {
            return array('请登陆后进行操作', 'error', AnUrl('user/login'));
        }
        if ($order_id > 0) {
            $order_info = _uri('order', $order_id);
            if($order_info['user_id'] != $this->user_id) {
                return array('您的订单有误，请重新发起支付', 'error', AnUrl('order'));
            }
            if (!$order_info || $order_info['id'] < 1) {
                return array('支付超时，请重新发起支付', 'error', AnUrl('order'));
            }
            if ($order_info['progress'] > 1) {
                return array('支付超时，请重新发起支付', 'error', AnUrl('order'));
            }

            // 重置支付宝配置
            $this->alipay_config = array_merge($this->alipay_config, openapi_helper::get_order_pay_account($order_id));

            if (ONDEV) {
                $total_fee = 0.01;
            } else {
                $total_fee = $order_info['price'];
            }

            $request_id = date('YmdHis').random(10);
            $format     = 'xml';
            $version    = 'v2';

            /**
             * 请求参数
             */
            $direct_trade_create_req = array(
                'notify_url'          => AnUrl('openapi/alipay/m/notify_url'),
                'call_back_url'       => AnUrl('openapi/alipay/m/return_url'),
                'seller_account_name' => $this->alipay_config['seller_email'],
                'out_trade_no'        => order_helper::order_id_encode($order_id),
                'subject'             => order_helper::get_goods_title($order_id),
                'total_fee'           => $total_fee,
                'merchant_url'        => AnUrl('order/'.$order_id)
            );

            /**
             * 获取token参数
             */
            $para_token = array(
                "service"        => "alipay.wap.trade.create.direct",
                "partner"        => trim($this->alipay_config['partner']),
                "sec_id"         => trim($this->alipay_config['sign_type']),
                "format"         => $format,
                "v"              => $version,
                "req_id"         => $request_id,
                "req_data"       => $this->arrayToXml($direct_trade_create_req, 'direct_trade_create_req'),
                "_input_charset" => trim(strtolower($this->alipay_config['input_charset']))
            );

            // 获取token
            $request = $this->buildRequestPara($para_token);
            $result  = $this->getHttpResponsePOST($this->alipay_config['alipay_gateway_new'], $this->alipay_config['cacert'], $request);
            $result_arr    = $this->parseResponse($result);
            $request_token = $result_arr['request_token'];

            $req_data = array(
                    'request_token' => $request_token
                );
            //构造要请求的参数数组，无需改动
            $parameter = array(
                "service"        => "alipay.wap.auth.authAndExecute",
                "partner"        => trim($this->alipay_config['partner']),
                "sec_id"         => trim($this->alipay_config['sign_type']),
                "format"         => $format,
                "v"              => $version,
                "req_id"         => $request_id,
                "req_data"       => $this->arrayToXml($req_data, 'auth_and_execute_req'),
                "_input_charset" => trim(strtolower($this->alipay_config['input_charset']))
            );

            $request = $this->buildRequestPara($parameter);

            Response::redirect($this->alipay_config['alipay_gateway_new'].http_build_query($request));
        } else {
            return array('支付超时，请重新发起支付', 'error', AnUrl('order'));
        }

        /**
         * 请求参数
         */
        $direct_trade_create_req = array(
            'notify_url'          => AnUrl('openapi/alipay/m_pay/notify_url'),
            'call_back_url'       => AnUrl('openapi/alipay/m_pay/return_url'),
            'seller_account_name' => $this->alipay_config['seller_email'],
            'out_trade_no'        => order_helper::order_id_encode($order_id),
            'subject'             => order_helper::get_goods_title($order_id),
            'total_fee'           => $order_info['price'],
            'merchant_url'        => AnUrl('order/'.$order_id)
        );

    }

    public function return_url()
    {
        require_once MODULE_PATH.'/openapi/helper/alipay/alipay_notify.class.php';

        try{

            $out_trade_no = $_GET['out_trade_no'];   //商户订单号

            if ($out_trade_no) {
                $order_id = order_helper::order_id_decode($out_trade_no);
                if(!is_numeric($order_id)) {
                    throw new Exception("订单不存在");
                }
                $order_id = (int)$order_id;
                if(!$order_id) {
                    throw new Exception("订单不存在");
                }
                $order_info = _uri('order', $order_id);
                if(!$order_info) {
                    throw new Exception("订单未找到");
                }

                $this->alipay_config = array_merge($this->alipay_config, openapi_helper::get_order_pay_account($order_id));
                $alipayNotify  = new AlipayNotify($this->alipay_config);
                $verify_result = $alipayNotify->verifyReturn();
                if(!$verify_result) {
                    throw new Exception("响应时间过期");
                }

                Response::assign('order_info', $order_info);

                Response::display('m_pay_success.html');
                /*
                if ($order_info['order_status'] == 2) {
                    return array('交易成功，等待商家发货！', 'error', AnUrl('order/m'));
                } else {
                    return array('支付宝交易正在处理中，等耐心等待', 'error', AnUrl('order/m'));
                }*/
            }
        } catch(Exception $exp) {
            log_helper::create_pay_log('alipay', array(
                'transaction_id' => '',
                'order_id'       => '',
                'total_price'    => '',
                'trade_status'   => 'error',
                'remarks'        => 'Alipay/m支付失败:'.$exp->getMessage()
            ));
            return array($exp->getMessage(), 'error', AnUrl('order'));
        }
    }

    public function notify_url()
    {
        require_once MODULE_PATH.'/openapi/helper/alipay/alipay_notify.class.php';

        try{

            $doc = new DOMDocument();
            $doc->loadXML($_POST['notify_data']);
            if(empty($doc->getElementsByTagName( "notify" )->item(0)->nodeValue) ) {
               throw new Exception("返回数据有误");
            }

            $out_trade_no = $doc->getElementsByTagName( "out_trade_no" )->item(0)->nodeValue;
            $trade_no     = $doc->getElementsByTagName( "trade_no" )->item(0)->nodeValue;
            $trade_status = $doc->getElementsByTagName( "trade_status" )->item(0)->nodeValue;
            $total_price  = $doc->getElementsByTagName( "total_price" )->item(0)->nodeValue;

            if($trade_status == 'TRADE_FINISHED' || $trade_status == 'TRADE_SUCCESS') {
                $order_id = order_helper::order_id_decode($out_trade_no);
                if(!is_numeric($order_id)) {
                    throw new Exception("订单不存在");
                }
                $order_id = (int)$order_id;
                if(!$order_id) {
                    throw new Exception("订单不存在");
                }
                $order_info = _uri('order', $order_id);
                if(!$order_info) {
                    throw new Exception("订单未找到");
                }

                $this->alipay_config = array_merge($this->alipay_config, openapi_helper::get_order_pay_account($order_id));

                $alipayNotify  = new AlipayNotify($this->alipay_config);
                $alipayNotify->setType(true);
                $verify_result = $alipayNotify->verifyNotify();
                if(!$verify_result) {
                    throw new Exception(json_encode($_POST));
                    throw new Exception("后台通知链接错误！");
                }

                $info['progress'] = 10;
                $info['transaction_id'] = $trade_no;
                $info['pay_time'] = date('Y-m-d H:i:s', time());

                if ($order_info['progress'] == 1 ) {
                    _model('order')->update(array('id'=>$order_id), $info);

                    //增加销量
                    order_helper::add_sale_num($order_id);

                    _widget('erp_lenovo.erp_lenovo_order')->AddOrder($order_id);

                    $mobile = Config::get('admin_mobile');
                    if ($mobile) {
                        order_helper::sendExpressMessage('pay_success', array(order_helper::order_id_encode($order_id)), $mobile);
                    }
                }
            }

            if ($trade_status == 'TRADE_CLOSED') {
                throw new Exception("当前交易被关闭！");
            }

            log_helper::create_pay_log('alipay', array(
                'transaction_id' => $trade_no,
                'order_id'       => order_helper::order_id_decode($out_trade_no),
                'total_price'    => $total_price,
                'trade_status'   => 'success',
                'remarks'        => '支付成功，当前通知为异步通知'
            ));

            echo 'success';
        } catch(Exception $exp) {
            log_helper::create_pay_log('alipay', array(
                'transaction_id' => '',
                'order_id'       => '',
                'total_price'    => '',
                'trade_status'   => 'error',
                'remarks'        => 'Alipay/m支付失败:'.$exp->getMessage()
            ));
            echo 'fail';
        }
    }

    /**
     *  作用：array转xml
     */
    private function arrayToXml($arr, $name)
    {
        $xml = "<".$name.">";
        foreach ($arr as $key=>$val) {
            $xml.="<".$key.">".$val."</".$key.">";
        }
        $xml.="</".$name.">";
        return $xml;
    }

    /**
     * 生成要请求给支付宝的参数数组
     * @param $para_temp 请求前的参数数组
     * @return 要请求的参数数组
     */
    function buildRequestPara($para_temp) {
        //除去待签名参数数组中的空值和签名参数
        $para_filter = openapi_helper::param_filter($para_temp);

        //对待签名参数数组排序
        $para_sort = openapi_helper::param_sort($para_filter);

        //生成签名结果
        $mysign = openapi_helper::build_request_sign($para_sort, $this->alipay_config['key'], 'alipay', $this->alipay_config['sign_type']);

        //签名结果与签名方式加入请求提交参数组中
        $para_sort['sign'] = $mysign;
        if($para_sort['service'] != 'alipay.wap.trade.create.direct' && $para_sort['service'] != 'alipay.wap.auth.authAndExecute') {
            $para_sort['sign_type'] = strtoupper(trim($this->alipay_config['sign_type']));
        }

        return $para_sort;
    }

    /**
     * 模拟post请求
     */
    private function getHttpResponsePOST($url, $cacert_url, $para)
    {
        $curl = curl_init($url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//严格认证
        curl_setopt($curl, CURLOPT_CAINFO,$cacert_url);//证书地址
        curl_setopt($curl, CURLOPT_HEADER, 0 ); // 过滤HTTP头
        curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
        curl_setopt($curl,CURLOPT_POST,true); // post传输数据
        curl_setopt($curl,CURLOPT_POSTFIELDS,$para);// post传输数据
        $responseText = curl_exec($curl);
        //var_dump( curl_error($curl) );//如果执行curl过程中出现异常，可打开此开关，以便查看异常内容
        curl_close($curl);

        return urldecode($responseText);
    }

    /**
     * 解析远程模拟提交后返回的信息
     * @param $str_text 要解析的字符串
     * @return 解析结果
     */
    function parseResponse($str_text) {
        //以“&”字符切割字符串
        $para_split = explode('&',$str_text);
        //把切割后的字符串数组变成变量与数值组合的数组
        foreach ($para_split as $item) {
            //获得第一个=字符的位置
            $nPos = strpos($item,'=');
            //获得字符串长度
            $nLen = strlen($item);
            //获得变量名
            $key = substr($item,0,$nPos);
            //获得数值
            $value = substr($item,$nPos+1,$nLen-$nPos-1);
            //放入数组中
            $para_text[$key] = $value;
        }

        if( ! empty ($para_text['res_data'])) {
            //解析加密部分字符串
            if($this->alipay_config['sign_type'] == '0001') {
                $para_text['res_data'] = openapi_helper::rsa_decrypt($para_text['res_data'], $this->alipay_config['private_key_path']);
            }

            //token从res_data中解析出来（也就是说res_data中已经包含token的内容）
            $doc = new DOMDocument();
            $doc->loadXML($para_text['res_data']);
            $para_text['request_token'] = $doc->getElementsByTagName( "request_token" )->item(0)->nodeValue;
        }

        return $para_text;
    }
}
?>